home *** CD-ROM | disk | FTP | other *** search
/ Delphi 2.0 - Programmer's Utilities Power Pack / Delphi 2.0 Programmer's Utilities Power Pack.iso / a_to_d / dwsock11 / dwinsock.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-09-15  |  21.6 KB  |  904 lines

  1. {--------------------------------------------------------------
  2.     WinSock component for Borland Delphi.
  3.  
  4.     (C) 1995 by Ulf S÷derberg, ulfs@sysinno.se
  5.  
  6.   History
  7.       V1.0        950404        US            First release.
  8.  
  9.     Parts of this code was inspired by WINSOCK.PAS by Marc B. Manza.
  10. ---------------------------------------------------------------}
  11.  
  12. unit DWinSock;
  13.  
  14. interface
  15.  
  16. uses
  17.     SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  18.     Forms, Dialogs;
  19.  
  20. const
  21.     CM_SOCKMSG    = WM_USER+1;
  22.     MAXCONN            = 16;                                        { allow 16 clients for TServerSockets }
  23.  
  24. {$I winsock.inc }
  25. {$I winsock.if }
  26.  
  27. type
  28.     { DWinSock exception type }
  29.     ESockError = class(Exception);
  30.  
  31.   TSocket = class;                                        { Forward declaration }
  32.  
  33.     { Socket info codes }
  34.   TSockInfo = (siLookUp, siConnect, siListen, siRecv, siSend);
  35.  
  36.     {    Define notification events for socket controls. }
  37.     TSockInfoEvent = procedure (Sender : TObject; icode : TSockInfo) of object;
  38.     TClientEvent = TNotifyEvent;
  39.     TServerEvent = procedure (Sender : TObject; cid : integer) of object;
  40.  
  41.     {    TSockCtrl -- socket control component base class. }
  42.     TSockCtrl = class(TCustomControl)
  43.     private
  44.         {    Event handler references }
  45.         FOnInfo                    : TSockInfoEvent;
  46.  
  47.         { Design tim connection info }
  48.         FHost                        : string;
  49.     FAddress                : string;
  50.         FService                : string;
  51.     FPort                        : u_short;
  52.  
  53.     { Run time connection info }
  54.         FConn                        : TSocket;
  55.  
  56.         { Design time bitmap }
  57.     FPicture                : TBitmap;
  58.  
  59.         { Access functions }
  60.         procedure SetService(const s : string);
  61.         procedure SetHost(const n : string);
  62.         procedure SetAddress(const a : string);
  63.         procedure SetPort(p : u_short);
  64.  
  65.         { Returns the WinSock.DLL description }
  66.         function GetDescription : string;
  67.  
  68.     protected
  69.         { Protected declarations }
  70.         constructor Create(AOwner : TComponent); override;
  71.         destructor Destroy; override;
  72.         procedure Paint; override;
  73.         procedure OnSizeChanged(var Message : TWMSize); message WM_SIZE;
  74.  
  75.     public
  76.         { Public declarations }
  77.     procedure Info(icode : TSockInfo);
  78.         function LocalHost : string;
  79.         function Reverse(var a : string) : string;
  80.  
  81.         property Conn : TSocket read FConn;
  82.         property Description : string read GetDescription;
  83.  
  84.     published
  85.         { Published declarations }
  86.         property Address : string read FAddress write SetAddress;
  87.         property Port : u_short read FPort write SetPort;
  88.         property Service : string read FService write SetService;
  89.     property OnInfo : TSockInfoEvent read FOnInfo write FOnInfo;
  90.     end;
  91.  
  92.     { Definition of the TClientSocket component class }
  93.     TClientSocket = class(TSockCtrl)
  94.     private
  95.         {    Event handler references }
  96.         FOnConnect            : TClientEvent;
  97.         FOnDisconnect        : TClientEvent;
  98.         FOnRead                    : TClientEvent;
  99.         FOnWrite                : TClientEvent;
  100.  
  101.     protected
  102.         { Protected declarations }
  103.         procedure OnSockMsg(var Message : TMessage); message CM_SOCKMSG;
  104.  
  105.     public
  106.         { Public declarations }
  107.     procedure Open;
  108.         procedure Close;
  109.         function SendBuf(var buf; cnt : integer) : integer;
  110.         function RecvBuf(var buf; cnt : integer) : integer;
  111.  
  112.     function GetBytesSent : integer;
  113.         function RecvText : string;
  114.     procedure SendText(const s : string);
  115.  
  116.     property BytesSent : integer read GetBytesSent;
  117.     property Text : string read RecvText write SendText;
  118.  
  119.     published
  120.         { Published declarations }
  121.          constructor Create(AOwner : TComponent); override;
  122.         destructor Destroy; override;
  123.  
  124.         property Host : string read FHost write SetHost;
  125.  
  126.         property OnConnect : TClientEvent read FOnConnect write FOnConnect;
  127.         property OnDisconnect : TClientEvent read FOnDisconnect write FOnDisconnect;
  128.         property OnRead : TClientEvent read FOnRead write FOnRead;
  129.         property OnWrite : TClientEvent read FOnWrite write FOnWrite;
  130.     property OnInfo;
  131.     end;
  132.  
  133.     { Definition of the TServerSocket component class }
  134.     TServerSocket = class(TSockCtrl)
  135.     private
  136.         {    Event handler references }
  137.         FOnAccept                : TServerEvent;
  138.         FOnDisconnect        : TServerEvent;
  139.         FOnRead                    : TServerEvent;
  140.         FOnWrite                : TServerEvent;
  141.  
  142.         FConns                    : array [1..MAXCONN] of TSocket;
  143.  
  144.         function GetClient(cid : integer) : TSocket;
  145.  
  146.         function DoAccept : integer;
  147.  
  148.     protected
  149.         { Protected declarations }
  150.         procedure OnSockMsg(var Message : TMessage); message CM_SOCKMSG;
  151.  
  152.     public
  153.         { Public declarations }
  154.          constructor Create(AOwner : TComponent); override;
  155.         destructor Destroy; override;
  156.  
  157.     procedure Listen(nqlen : integer);
  158.         procedure Close;
  159.  
  160.         { Return client socket }
  161.         property Client[cid : integer] : TSocket read GetClient; default;
  162.  
  163.     published
  164.         { Published declarations }
  165.         property OnAccept : TServerEvent read FOnAccept write FOnAccept;
  166.         property OnDisconnect : TServerEvent read FOnDisconnect write FOnDisconnect;
  167.         property OnRead : TServerEvent read FOnRead write FOnRead;
  168.         property OnWrite : TServerEvent read FOnWrite write FOnWrite;
  169.         property OnInfo;
  170.     end;
  171.  
  172.     { TSocket -- socket api wrapper class. }
  173.     TSocket = class(TObject)
  174.     public
  175.         FParent                    : TSockCtrl;                        { socket owner }
  176.         FSocket                    : TSock;                                { socket id }
  177.         FAddr                        : sockaddr_in;                    { host address }
  178.         FConnected            : boolean;
  179.         FBytesSent            : integer;                            { bytes sent by last SendBuf call }
  180.  
  181.         constructor Create(AParent : TSockCtrl);
  182.         destructor Destroy;
  183.  
  184.     function LookupName(var name : string) : in_addr;
  185.     function LookupService(var service : string) : u_short;
  186.         procedure FillSocket(var name, addr, service : string; var port : u_short);
  187.  
  188.         function LocalAddress : string;
  189.         function LocalPort : integer;
  190.  
  191.         function RemoteHost : string;
  192.         function RemoteAddress : string;
  193.         function RemotePort : integer;
  194.  
  195.         procedure Listen(var name, addr, service : string; port : u_short; nqlen : integer);
  196.         procedure Open(var name, addr, service : string; port : u_short);
  197.         procedure Close;
  198.  
  199.         function SendBuf(var buf; cnt : integer) : integer;
  200.         function RecvBuf(var buf; cnt : integer) : integer;
  201.  
  202.         function RecvText : string;
  203.     procedure SendText(const s : string);
  204.  
  205.     property BytesSent : integer read FBytesSent;
  206.     property Text : string read RecvText write SendText;
  207.     end;
  208.  
  209. procedure Register;
  210.  
  211. implementation
  212.  
  213. {$R DWINSOCK}
  214.  
  215. var
  216.     ExitSave    : Pointer;
  217.     bStarted  : boolean;
  218.     nUsers    : integer;
  219.     nWSErr    : integer;
  220.     myVerReqd : word;
  221.   myWSAData : WSADATA;
  222.  
  223. {$I ERROR.INC}
  224.  
  225. { StartUp -- See if a Windows Socket DLL is present on the system. }
  226. procedure StartUp;
  227. begin
  228.     if bStarted then exit;
  229.   nUsers := 0;
  230.     myVerReqd:=$0101;
  231.     nWSErr := WSAStartup(myVerReqd,@myWSAData);
  232.     if nWSErr = 0 then
  233.         bStarted := true
  234.     else
  235.         raise ESockError.Create('Can''t startup WinSock');
  236. end;
  237.  
  238. { CleanUp -- Tell Windows Socket DLL we don't need its services any longer. }
  239. procedure CleanUp; far;
  240. begin
  241.     ExitProc := ExitSave;
  242.     if bStarted then
  243.     begin
  244.       nWSErr := WSACleanup;
  245.       bStarted := false;
  246.         end;
  247. end;
  248.  
  249. {--------------------------------------------------------------
  250.     TSocket implementation
  251.  --------------------------------------------------------------}
  252.  
  253. constructor TSocket.Create(AParent : TSockCtrl);
  254. begin
  255.     inherited Create;
  256.   FParent := AParent;
  257.     FSocket := INVALID_SOCKET;
  258.     FAddr.sin_family := PF_INET;
  259.     FAddr.sin_addr.s_addr := INADDR_ANY;
  260.   FAddr.sin_port := 0;
  261.     FConnected := false;
  262.     FBytesSent := 0;
  263. end;
  264.  
  265. destructor TSocket.Destroy;
  266. begin
  267.     if FConnected {or (FSocket <> INVALID_SOCKET)} then
  268.         CloseSocket(FSocket);
  269.     inherited Destroy;
  270. end;
  271.  
  272. { LocalAddress -- get local address }
  273. function TSocket.LocalAddress : string;
  274. var
  275.     sa : sockaddr_in;
  276.     nl : integer;
  277. begin
  278.     Result := '';
  279.     if FSocket = INVALID_SOCKET then exit;
  280.     if getsockname(FSocket, PSockaddr(@sa), @nl) = 0 then
  281.         Result := StrPas(inet_ntoa(sa.sin_addr));
  282. end;
  283.  
  284. { LocalPort -- get local port number }
  285. function TSocket.LocalPort : integer;
  286. var
  287.     sa : sockaddr_in;
  288.     nl : integer;
  289. begin
  290.     Result := 0;
  291.     if FSocket = INVALID_SOCKET then exit;
  292.     if getsockname(FSocket, PSockaddr(@sa), @nl) = 0 then
  293.         Result := ntohs(sa.sin_port);
  294. end;
  295.  
  296. { RemoteHost -- get name of connected remote host }
  297. function TSocket.RemoteHost : string;
  298. var
  299.     sa    : sockaddr_in;
  300.   nl    : integer;
  301.     phe : PHostEnt;
  302. begin
  303.     Result := '';
  304.     if not FConnected then exit;
  305.     { Get connection address info }
  306.     getpeername(FSocket, PSockaddr(@sa), @nl);
  307.     FAddr := sa;
  308.   { Do a reverse lookup to get the host name }
  309.     phe := gethostbyaddr(PChar(@FAddr.sin_addr.s_addr), 4, PF_INET);
  310.     if phe <> nil then
  311.         Result := StrPas(phe^.h_name);
  312. end;
  313.  
  314. { RemoteAddress -- get address of connected remote host }
  315. function TSocket.RemoteAddress : string;
  316. var
  317.     sa : sockaddr_in;
  318.     nl : integer;
  319. begin
  320.     Result := '?';
  321.     if (FSocket = INVALID_SOCKET) or (not FConnected) then exit;
  322.     if getpeername(FSocket, PSockaddr(@sa), @nl) = 0 then
  323.         Result := StrPas(inet_ntoa(sa.sin_addr));
  324. end;
  325.  
  326. { RemotePort -- get remote port number }
  327. function TSocket.RemotePort : integer;
  328. var
  329.     sa : sockaddr_in;
  330.     nl : integer;
  331. begin
  332.     Result := 0;
  333.     if (FSocket = INVALID_SOCKET) or (not FConnected) then exit;
  334.     if getpeername(FSocket, PSockaddr(@sa), @nl) = 0 then
  335.         Result := ntohs(sa.sin_port)
  336.     else
  337.         Result := 0;
  338. end;
  339.  
  340. { LookupName -- try to look up host name }
  341. function TSocket.LookupName(var name : string) : in_addr;
  342. var
  343.     phe    : PHostEnt;
  344.     sz    : array [1..64] of char;
  345.   sa    : in_addr;
  346. begin
  347.     StrPCopy(@sz, name);
  348.     phe := gethostbyname(@sz);
  349.     if phe <> nil then
  350.         begin
  351.             phe^.h_addr := phe^.h_addr_list^;
  352.             sa.S_un_b.s_b1:=phe^.h_addr[0];
  353.             sa.S_un_b.s_b2:=phe^.h_addr[1];
  354.             sa.S_un_b.s_b3:=phe^.h_addr[2];
  355.             sa.S_un_b.s_b4:=phe^.h_addr[3];
  356.       Result := sa;
  357.     end
  358.   else
  359.       raise ESockError.Create('Can''t find host ' + name);
  360. end;
  361.  
  362. { LookupService -- try to lookup service name }
  363. function TSocket.LookupService(var service : string) : u_short;
  364. var
  365.     ps    : PServEnt;
  366.     proto    : array [1..32] of char;
  367.     name : array [1..64] of char;
  368. begin
  369.     Result := 0;
  370.     StrPCopy(@proto, 'tcp');
  371.     StrPCopy(@name, service);
  372.     ps := getservbyname(@name, @proto);
  373.     if ps <> nil then
  374.         Result := ps^.s_port
  375.     else
  376.         raise ESockError.Create('Can''t find port for service ' + service);
  377. end;
  378.  
  379. { FillSocket -- fill in address and port fields in socket struct }
  380. procedure TSocket.FillSocket(var name, addr, service : string; var port : u_short);
  381. var
  382.     s    : array [1..32] of char;
  383. begin
  384.     { Fill in address field }
  385.     if name <> '' then                        { Host name given }
  386.       begin
  387.           FAddr.sin_addr := LookupName(name);
  388.       addr := StrPas(inet_ntoa(FAddr.sin_addr));
  389.     end
  390.   else if addr <> '' then                { IP address given }
  391.       begin
  392.           StrPCopy(@s, addr);
  393.           FAddr.sin_addr.s_addr := inet_addr(@s);
  394.     end
  395.     else                                                    { Neither name or address given }
  396.       raise ESockError.Create('No address specified');
  397.  
  398.     { Fill in port number field }
  399.   if service <> '' then
  400.       begin
  401.             FAddr.sin_port := LookupService(service);
  402.       port := ntohs(FAddr.sin_port);
  403.     end
  404.   else
  405.       FAddr.sin_port := htons(port);
  406. end;
  407.  
  408. { Listen -- wait for incoming connection. }
  409. procedure TSocket.Listen(var name, addr, service : string; port : u_short; nqlen : integer);
  410. var
  411.     q, e    : integer;
  412. begin
  413.     if (not bStarted) then
  414.       raise ESockError.Create('WINSOCK not started');
  415.  
  416.     FSocket := DWinsock.socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
  417.     if FSocket = INVALID_SOCKET then
  418.       raise ESockError.Create('Can''t create new socket');
  419.  
  420.   FillSocket(name, addr, service, port);
  421.  
  422.     if bind(FSocket, Psockaddr(@FAddr), SizeOf(FAddr)) <> 0 then
  423.         begin
  424.         e := WSAGetLastError;
  425.             Close;
  426.             raise ESockError.Create('Bind failed, '+Error(e));
  427.         end;
  428.  
  429.     WSAAsyncSelect(FSocket, FParent.Handle, CM_SOCKMSG, FD_ACCEPT or FD_CLOSE or FD_READ or FD_WRITE);
  430.  
  431.     q := MAXCONN;
  432.     if nqlen < q then
  433.         q := nqlen;
  434.  
  435.     if DWinsock.listen(FSocket, q) <> 0 then
  436.         begin
  437.             e := WSAGetLastError;
  438.             Close;
  439.             raise ESockError.Create('Listen failed, '+Error(e));
  440.         end;
  441. end;
  442.  
  443. {    Open a connection. }
  444. procedure TSocket.Open(var name, addr, service : string; port : u_short);
  445. begin
  446.     if (not bStarted) then
  447.       raise ESockError.Create('WINSOCK not started');
  448.  
  449.   if FConnected then
  450.       raise ESockError.Create('Can''t open an open socket');
  451.  
  452.     FSocket := DWinsock.socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
  453.     if FSocket = INVALID_SOCKET then
  454.       raise ESockError.Create('Can''t create new socket');
  455.  
  456.   FParent.Info(siLookUp);
  457.   FillSocket(name, addr, service, port);
  458.  
  459.     WSAAsyncSelect(FSocket, FParent.Handle, CM_SOCKMSG, FD_CONNECT or FD_CLOSE or FD_READ or FD_WRITE);
  460.  
  461.   FParent.Info(siConnect);
  462.     if connect(FSocket, Psockaddr(@FAddr), SizeOf(FAddr)) <> 0 then
  463.         if WSAGetLastError <> WSAEWOULDBLOCK then
  464.             begin
  465.                 Close;
  466.                 raise ESockError.Create('Open failed');
  467.             end;
  468. end;
  469.  
  470. procedure TSocket.Close;
  471. begin
  472.     if (not bStarted) or (FSocket = INVALID_SOCKET) then exit;
  473.     closesocket(FSocket);
  474.     {FSocket := INVALID_SOCKET;}
  475.   FConnected := false;
  476.     FBytesSent := 0;
  477. end;
  478.  
  479. function TSocket.RecvText : string;
  480. var
  481.   n        : integer;
  482. begin
  483.     n := RecvBuf(PChar(@Result[1])^, 255);
  484.   Result[0] := char(n);
  485. end;
  486.  
  487. procedure TSocket.SendText(const s : string);
  488. begin
  489.     FBytesSent := SendBuf(PChar(@s[1])^, Length(s));
  490. end;
  491.  
  492. {    Send contents of passed buffer. }
  493. function TSocket.SendBuf(var buf; cnt : integer) : integer;
  494. var
  495.     n : integer;
  496. begin
  497.     Result := 0;
  498.     if (FSocket = INVALID_SOCKET) or (not FConnected) then exit;
  499.     n := send(FSocket, @buf, cnt, 0);
  500.     if n > 0 then
  501.         Result := n
  502.     else if (n = SOCKET_ERROR) and (WSAGetLastError <> WSAEWOULDBLOCK) then
  503.       begin
  504.             Close;
  505.       raise ESockError.Create('Send error');
  506.     end;
  507. end;
  508.  
  509. {    Request that passed buffer be filled with received data. }
  510. function TSocket.RecvBuf(var buf; cnt : integer) : integer;
  511. var
  512.     n : integer;
  513. begin
  514.     Result := 0;
  515.  
  516.     if (FSocket = INVALID_SOCKET) or (not FConnected) then
  517.       raise ESockError.Create('Socket not open');
  518.  
  519.     n := recv(FSocket, @buf, cnt, 0);
  520.     if n > 0 then
  521.         Result := n
  522.   else if (n = SOCKET_ERROR) and (WSAGetLastError <> WSAEWOULDBLOCK) then
  523.       begin
  524.         Close;
  525.           raise ESockError.Create('Recv error');
  526.     end;
  527. end;
  528.  
  529. {--------------------------------------------------------------
  530.     TSockCtrl implementation
  531.  --------------------------------------------------------------}
  532.  
  533. { Create -- initalization }
  534. constructor TSockCtrl.Create(AOwner : TComponent);
  535. begin
  536.     inherited Create(AOwner);
  537.     FConn := TSocket.Create(self);
  538.     { Create design bitmap }
  539.     FPicture := TBitmap.Create;
  540.  
  541.     { The control should be visible at design time only.
  542.       At run time, check if the WINSOCK has been started. }
  543.     if csDesigning in ComponentState then
  544.         Visible := true
  545.     else
  546.       begin
  547.             Visible := false;
  548.           StartUp;
  549.     end;
  550.  
  551.   FHost := '';
  552.   FAddress := '0.0.0.0';
  553.  
  554.   FService := '';
  555.   FPort := 0;
  556.  
  557.     inc(nUsers);
  558. end;
  559.  
  560. { Destroy -- destruction }
  561. destructor TSockCtrl.Destroy;
  562. var
  563.     res : integer;
  564. begin
  565.      FConn.Destroy;
  566.     dec(nUsers);
  567.   if nUsers <= 0 then
  568.         CleanUp;
  569.   FPicture.Destroy;
  570.     inherited Destroy;
  571. end;
  572.  
  573. { OnSizeChanged -- this procedure is called at design time if the designer
  574.     is trying to resize the control on the form. It will force the control to
  575.   be the size of the bitmap. }
  576. procedure TSockCtrl.OnSizeChanged(var Message : TWMSize);
  577. begin
  578.     Height := FPicture.Height;
  579.   Width := FPicture.Width;
  580. end;
  581.  
  582. { Paint -- show the bitmap at design time. }
  583. procedure TSockCtrl.Paint;
  584. begin
  585.     if csDesigning in ComponentState then
  586.         Canvas.Draw(0, 0, FPicture);
  587. end;
  588.  
  589. { Info -- call the OnInfo event handler if any. }
  590. procedure TSockCtrl.Info(icode : TSockInfo);
  591. begin
  592.     if Assigned(FOnInfo) then
  593.       FOnInfo(self, icode);
  594. end;
  595.  
  596. { GetDescription -- return description of WinSock implementation }
  597. function TSockCtrl.GetDescription : string;
  598. begin
  599.     Result := StrPas(myWSAdata.szDescription);
  600. end;
  601.  
  602. { LocalHost -- return name of local host }
  603. function TSockCtrl.LocalHost : string;
  604. var
  605.     sh : array [0..255] of char;
  606. begin
  607.     if not bStarted then
  608.         begin
  609.             Result := '';
  610.             exit;
  611.         end;
  612.     if gethostname(sh, 255) = 0 then
  613.         Result := StrPas(sh)
  614.     else
  615.         Result := '';
  616. end;
  617.  
  618. { Set host name }
  619. procedure TSockCtrl.SetHost(const n : string);
  620. begin
  621.     FHost := n;
  622.   FAddress := '';
  623. end;
  624.  
  625. { Set host address }
  626. procedure TSockCtrl.SetAddress(const a : string);
  627. begin
  628.     FAddress := a;
  629.   FHost := '';
  630. end;
  631.  
  632. { Set service name }
  633. procedure TSockCtrl.SetService(const s : string);
  634. begin
  635.     FService := s;
  636.   FPort := 0;
  637. end;
  638.  
  639. { Set port number }
  640. procedure TSockCtrl.SetPort(p : u_short);
  641. begin
  642.     FPort := p;
  643.   FService := '';
  644. end;
  645.  
  646. { Reverse -- try to do a reverse lookup }
  647. function TSockCtrl.Reverse(var a : string) : string;
  648. var
  649.     phe    : PHostEnt;
  650.     s        : array[0..31] of char;
  651.     sa    : in_addr;
  652. begin
  653.     StrPCopy(s, a);
  654.     sa.s_addr := inet_addr(s);
  655.     if sa.s_addr = 0 then
  656.         raise ESockError.Create('Can''t do reverse lookup on address 0.0.0.0');
  657.  
  658.     phe := gethostbyaddr(PChar(@sa.s_addr), 4, PF_INET);
  659.     if phe <> nil then
  660.         Result := StrPas(phe^.h_name)
  661.     else
  662.         raise ESockError.Create('Reverse lookup on ' + a + ' failed');
  663. end;
  664.  
  665. {--------------------------------------------------------------
  666.     TClientSocket implementation.
  667.  --------------------------------------------------------------}
  668.  
  669. constructor TClientSocket.Create(AOwner : TComponent);
  670. begin
  671.     inherited Create(AOwner);
  672.   FPicture.Handle := LoadBitmap(HInstance, 'CLIENT');
  673. end;
  674.  
  675. destructor TClientSocket.Destroy;
  676. begin
  677.     inherited Destroy;
  678. end;
  679.  
  680. procedure TClientSocket.Open;
  681. begin
  682.     FConn.Open(FHost, FAddress, FService, FPort);
  683. end;
  684.  
  685. procedure TClientSocket.Close;
  686. begin
  687.     FConn.Close;
  688. end;
  689.  
  690. function TClientSocket.GetBytesSent : integer;
  691. begin
  692.     Result := FConn.FBytesSent;
  693. end;
  694.  
  695. function TClientSocket.RecvText : string;
  696. begin
  697.     Result := FConn.RecvText;
  698. end;
  699.  
  700. procedure TClientSocket.SendText(const s : string);
  701. begin
  702.     FConn.SendText(s);
  703. end;
  704.  
  705. function TClientSocket.SendBuf(var buf; cnt : integer) : integer;
  706. begin
  707.     Result := FConn.SendBuf(buf, cnt);
  708. end;
  709.  
  710. function TClientSocket.RecvBuf(var buf; cnt : integer) : integer;
  711. begin
  712.     Result := FConn.RecvBuf(buf, cnt);
  713. end;
  714.  
  715. procedure TClientSocket.OnSockMsg(var Message : TMessage);
  716.     var
  717.         sock : TSock;
  718.         evt, err : word;
  719.     begin
  720.         sock := TSock(Message.wParam);
  721.         evt := WSAGetSelectEvent(Message.lParam);
  722.         err := WSAGetSelectError(Message.lParam);
  723.  
  724.         case evt of
  725.             FD_CONNECT:
  726.                 begin
  727.                     FConn.FConnected := true;
  728.                     if Assigned(FOnConnect) then
  729.                         FOnConnect(self);
  730.                 end;
  731.  
  732.             FD_CLOSE:
  733.                 begin
  734.                     if FConn.FConnected then
  735.                         closesocket(FConn.FSocket);
  736.                     FConn.FConnected := false;
  737.                     FConn.FSocket := INVALID_SOCKET;
  738.                     if Assigned(FOnDisconnect) then
  739.                         FOnDisconnect(self);
  740.                 end;
  741.  
  742.             FD_OOB: ;
  743.             FD_READ:
  744.                 if Assigned(FOnRead) then
  745.                     FOnRead(self);
  746.  
  747.             FD_WRITE:
  748.                 if Assigned(FOnWrite) then
  749.                     FOnWrite(self);
  750.         end;
  751.     end;
  752.  
  753. {--------------------------------------------------------------
  754.     TServerSocket functions
  755.  --------------------------------------------------------------}
  756.  
  757. constructor TServerSocket.Create(AOwner : TComponent);
  758. var
  759.     i    : integer;
  760. begin
  761.     inherited Create(AOwner);
  762.     for i := 1 to MAXCONN do
  763.         FConns[i] := TSocket.Create(self);
  764.   FPicture.Handle := LoadBitmap(HInstance, 'SERVER');
  765. end;
  766.  
  767. destructor TServerSocket.Destroy;
  768. var
  769.     i : integer;
  770. begin
  771.     for i := 1 to MAXCONN do
  772.         FConns[i].Destroy;
  773.     inherited Destroy;
  774. end;
  775.  
  776. function TServerSocket.GetClient(cid : integer) : TSocket;
  777.     begin
  778.         Result := FConns[cid];
  779.     end;
  780.  
  781. procedure TServerSocket.Close;
  782. begin
  783.     FConn.Close;
  784. end;
  785.  
  786. procedure TServerSocket.OnSockMsg(var Message : TMessage);
  787. var
  788.     sock    : TSock;
  789.     evt        : word;
  790.   err        : word;
  791.     cid        : integer;
  792.  
  793.     procedure FindConn;
  794.     var
  795.         i        : integer;
  796.     begin
  797.         cid := 0;
  798.         for i := 1 to MAXCONN do
  799.             if FConns[i].FSocket = sock then
  800.                 begin
  801.                     cid := i;
  802.                     exit;
  803.                 end;
  804.     end;
  805.  
  806. begin
  807.     sock := TSock(Message.wParam);
  808.     evt := WSAGetSelectEvent(Message.lParam);
  809.     err := WSAGetSelectError(Message.lParam);
  810.  
  811.     case evt of
  812.         FD_ACCEPT:
  813.             begin
  814.                 cid := DoAccept;
  815.                 if Assigned(FOnAccept) and (cid > 0) then
  816.                     FOnAccept(self, cid);
  817.             end;
  818.  
  819.         FD_CLOSE:
  820.             begin
  821.                 FindConn;
  822.                 if not FConns[cid].FConnected then
  823.                     closesocket(FConns[cid].FSocket);
  824.                 FConns[cid].FConnected := false;
  825.                 FConns[cid].FSocket := INVALID_SOCKET;
  826.                 if Assigned(FOnDisconnect) then
  827.                     FOnDisconnect(self, cid);
  828.             end;
  829.  
  830.         FD_OOB: ;
  831.         FD_READ:
  832.             begin
  833.                 FindConn;
  834.                 if Assigned(FOnRead) then
  835.                     FOnRead(self, cid);
  836.             end;
  837.  
  838.         FD_WRITE:
  839.             begin
  840.                 FindConn;
  841.                 if Assigned(FOnWrite) then
  842.                     FOnWrite(self, cid);
  843.             end;
  844.     end;
  845. end;
  846.  
  847. function TServerSocket.DoAccept : integer;
  848. var
  849.     ts    : TSocket;
  850.     nl    : integer;
  851.     cid    : integer;
  852.  
  853.     function NewConn : integer;
  854.     var
  855.         i        : integer;
  856.     begin
  857.         Result := 0;
  858.         for i := 1 to MAXCONN do
  859.             if FConns[i].FSocket = INVALID_SOCKET then
  860.                 begin
  861.                     Result := i;
  862.                     exit;
  863.                 end;
  864.     end;
  865.  
  866. begin
  867.     Result := 0;
  868.     cid := NewConn;
  869.     ts := FConns[cid];
  870.     nl := sizeof(sockaddr_in);
  871.     ts.FSocket := accept(FConn.FSocket, PSockaddr(@ts.FAddr), @nl);
  872.     if ts.FSocket <> INVALID_SOCKET then
  873.         begin
  874.             {WSAAsyncSelect(ts.FSocket, Handle, CM_SOCKMSG, FD_CLOSE or FD_READ or FD_WRITE);}
  875.             ts.FConnected := true;
  876.             Result := cid;
  877.         end;
  878. end;
  879.  
  880. procedure TServerSocket.Listen(nqlen : integer);
  881. begin
  882.     FConn.Listen(FHost, FAddress, FService, FPort, nqlen);
  883. end;
  884.  
  885. {    Register our components. }
  886. procedure Register;
  887. begin
  888.     RegisterComponents('Samples', [TClientSocket]);
  889.     RegisterComponents('Samples', [TServerSocket]);
  890. end;
  891.  
  892. {$I winsock.imp }
  893.  
  894. {--------------------------------------------------------------
  895.     Unit initialization code.
  896.  --------------------------------------------------------------}
  897.  
  898. initialization
  899.     bStarted := false;
  900.     ExitSave := ExitProc;
  901.   ExitProc := @CleanUp;
  902. end.
  903.  
  904.